package com.daffodil.core.aspect;

import java.lang.reflect.Method;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.hibernate.engine.spi.SessionImplementor;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.daffodil.core.annotation.TargetDataSource;
import com.daffodil.core.jdbc.DaffodilDataSourceContextHolder;

import lombok.extern.slf4j.Slf4j;

/**
 *切换数据源切面
 * @author yweijian
 * @date 2021年9月1日
 * @version 1.0
 * @description
 */
@Slf4j
@Aspect
@Order(-1)//设置AOP执行顺序(需要在事务之前，否则事务只发生在默认库中
@Component
public class DaffodilDataSourceAspect {

	@PersistenceContext
    private EntityManager entityManager;
	
	@Pointcut("@annotation(com.daffodil.core.annotation.TargetDataSource)")
	public void daffodilDataSourcePointCut() {
		
	}
	
	@Before("daffodilDataSourcePointCut()")
	public void doBefore(JoinPoint joinPoint) throws Throwable {
		// 获得注解
		TargetDataSource targetDataSource = this.getAnnotationLog(joinPoint);
		if (targetDataSource == null) {
			return;
		}
		String dataSourceLookupKey = targetDataSource.value();
		if(DaffodilDataSourceContextHolder.containsDataSource(dataSourceLookupKey)) {
			DaffodilDataSourceContextHolder.setDataSourceLookupKey(dataSourceLookupKey);
		}else {
			log.info("数据源[{}]不存在，使用默认数据源 > {}", dataSourceLookupKey, "primary");
			DaffodilDataSourceContextHolder.setDataSourceLookupKey("primary");
		}
	}
	
	@After("daffodilDataSourcePointCut()")
	public void doAfter(JoinPoint joinPoint) {
		String dataSourceLookupKey = DaffodilDataSourceContextHolder.getDataSourceLookupKey();
		DaffodilDataSourceContextHolder.clearDataSourceLookupKey();
		SessionImplementor session = entityManager.unwrap(SessionImplementor.class);
		//方法执行完成后 会话断开回收
		session.disconnect();
		log.info("数据源[{}]会话连接断开", dataSourceLookupKey);
	}
	
	/**
	 * 是否存在注解，如果存在就获取
	 */
	private TargetDataSource getAnnotationLog(JoinPoint joinPoint) {
		Signature signature = joinPoint.getSignature();
		MethodSignature methodSignature = (MethodSignature) signature;
		Method method = methodSignature.getMethod();

		if (method != null) {
			return method.getAnnotation(TargetDataSource.class);
		}
		return null;
	}
}
